#include "pch.h"
#include "CharacterRenderer.h"
#include <algorithm>

namespace
{  
   std::vector<D2D1_POINT_2F> 
   CreateCharacters(float _scale)
   {
      float x = 0.0f;
      float y = 0.0f;

      std::vector<D2D1_POINT_2F> points;

      for (int vertical_axis= 0; vertical_axis < 7; vertical_axis++)
      {             
         y = vertical_axis * _scale;
         for (int horizontal_axis = 0; horizontal_axis < 5; ++horizontal_axis)
         {
            x = horizontal_axis * _scale;
            points.push_back(D2D1::Point2(x, y));
         }
      }   
      return points;
   }

   inline int ToIndex(char ch)
   {
      int index = tolower(ch);
      if (index >= '0' && index <= '9')
      {
         return index - '0';
      }
      if (index >= 'a' && index <= 'z')
      {
         return index - 'a' + 10;
      }
      return 36;
   }

   inline D2D1_POINT_2F Add(D2D1_POINT_2F const & _rhs, D2D1_POINT_2F const & _lhs)
   {
      return D2D1::Point2F(_rhs.x + _lhs.x, _rhs.y + _lhs.y);
   }
}


dxroids::CharacterRenderer::CharacterRenderer()
{   
   line_lists_.reserve(37);
   line_lists_.resize(37);

   point_list_type * p = nullptr;

   p = &(line_lists_[ToIndex('a')]);  
   p->push_back(std::make_pair(2, 14));
   p->push_back(std::make_pair(14, 34));
   p->push_back(std::make_pair(2, 10));
   p->push_back(std::make_pair(10, 30));
   p->push_back(std::make_pair(20, 24));

   p = &(line_lists_[ToIndex('b')]);
   p->push_back(std::make_pair(0, 3));
   p->push_back(std::make_pair(3, 9));
   p->push_back(std::make_pair(9, 14));
   p->push_back(std::make_pair(14, 18));
   p->push_back(std::make_pair(18, 24));
   p->push_back(std::make_pair(24, 29));
   p->push_back(std::make_pair(29, 33));
   p->push_back(std::make_pair(33, 30));
   p->push_back(std::make_pair(30, 0));
   p->push_back(std::make_pair(15, 18));   

   p = &(line_lists_[ToIndex('c')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(30, 34));

   p = &(line_lists_[ToIndex('d')]);
   p->push_back(std::make_pair(0, 2));
   p->push_back(std::make_pair(2, 14));
   p->push_back(std::make_pair(14, 24));
   p->push_back(std::make_pair(24, 32));
   p->push_back(std::make_pair(32, 30));
   p->push_back(std::make_pair(30, 0));

   p = &(line_lists_[ToIndex('e')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(15, 18));
   p->push_back(std::make_pair(30, 34));
   p->push_back(std::make_pair(30, 0));

   p = &(line_lists_[ToIndex('f')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(15, 18));
   p->push_back(std::make_pair(0, 30));

   p = &(line_lists_[ToIndex('g')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(4, 14));
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(30, 34));
   p->push_back(std::make_pair(34, 24));
   p->push_back(std::make_pair(24, 22));

   p = &(line_lists_[ToIndex('h')]);
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(4, 34));
   p->push_back(std::make_pair(15, 19));

   p = &(line_lists_[ToIndex('i')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(2, 32));
   p->push_back(std::make_pair(30, 34));

   p = &(line_lists_[ToIndex('j')]);
   p->push_back(std::make_pair(4, 34));
   p->push_back(std::make_pair(32, 34));
   p->push_back(std::make_pair(20, 32));

   p = &(line_lists_[ToIndex('k')]);
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(15, 4));
   p->push_back(std::make_pair(15, 34));

   p = &(line_lists_[ToIndex('l')]);
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(30, 34));

   p = &(line_lists_[ToIndex('m')]);
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(4, 34));
   p->push_back(std::make_pair(0, 12));
   p->push_back(std::make_pair(4, 12));

   p = &(line_lists_[ToIndex('n')]);
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(0, 34));
   p->push_back(std::make_pair(4, 34));

   p = &(line_lists_[ToIndex('o')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(4, 34));
   p->push_back(std::make_pair(34, 30));
   p->push_back(std::make_pair(30, 0));

   p = &(line_lists_[ToIndex('p')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(15, 19));
   p->push_back(std::make_pair(4, 19));

   p = &(line_lists_[ToIndex('q')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(30, 32));
   p->push_back(std::make_pair(32, 19));
   p->push_back(std::make_pair(19, 4));
   p->push_back(std::make_pair(22, 34));

   p = &(line_lists_[ToIndex('r')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(15, 19));
   p->push_back(std::make_pair(4, 19));
   p->push_back(std::make_pair(17, 34));

   p = &(line_lists_[ToIndex('s')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(0, 15));
   p->push_back(std::make_pair(15, 19));
   p->push_back(std::make_pair(19, 34));
   p->push_back(std::make_pair(34, 30));

   p = &(line_lists_[ToIndex('t')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(2, 32));

   p = &(line_lists_[ToIndex('u')]);
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(30, 34));
   p->push_back(std::make_pair(34, 4));

   p = &(line_lists_[ToIndex('v')]);
   p->push_back(std::make_pair(0, 32));
   p->push_back(std::make_pair(4, 32));

   p = &(line_lists_[ToIndex('w')]);
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(30, 22));
   p->push_back(std::make_pair(34, 22));
   p->push_back(std::make_pair(34, 4));

   p = &(line_lists_[ToIndex('x')]);
   p->push_back(std::make_pair(0, 34));
   p->push_back(std::make_pair(4, 30));

   p = &(line_lists_[ToIndex('y')]);
   p->push_back(std::make_pair(0, 17));
   p->push_back(std::make_pair(4, 17));
   p->push_back(std::make_pair(17, 32));

   p = &(line_lists_[ToIndex('z')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(4, 30));
   p->push_back(std::make_pair(30, 34));

   // digits
   p = &(line_lists_[ToIndex('0')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(4, 34));
   p->push_back(std::make_pair(30, 34));

   p = &(line_lists_[ToIndex('1')]);   
   p->push_back(std::make_pair(4, 34));   

   p = &(line_lists_[ToIndex('2')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(4, 19));
   p->push_back(std::make_pair(15, 19));
   p->push_back(std::make_pair(15, 30));
   p->push_back(std::make_pair(30, 34));

   p = &(line_lists_[ToIndex('3')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(15, 19));
   p->push_back(std::make_pair(30, 34));
   p->push_back(std::make_pair(4, 34));   
   
   p = &(line_lists_[ToIndex('4')]);
   p->push_back(std::make_pair(0, 15));
   p->push_back(std::make_pair(15, 19));
   p->push_back(std::make_pair(4, 34));

   p = &(line_lists_[ToIndex('5')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(0, 15));
   p->push_back(std::make_pair(15, 19));
   p->push_back(std::make_pair(19, 34));
   p->push_back(std::make_pair(34, 30));

   p = &(line_lists_[ToIndex('6')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(0, 30));
   p->push_back(std::make_pair(15, 19));
   p->push_back(std::make_pair(19, 34));
   p->push_back(std::make_pair(34, 30));

   p = &(line_lists_[ToIndex('7')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(4, 34));   

   p = &(line_lists_[ToIndex('8')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(4, 34));
   p->push_back(std::make_pair(34, 30));
   p->push_back(std::make_pair(30, 0));
   p->push_back(std::make_pair(15, 19));
   
   p = &(line_lists_[ToIndex('9')]);
   p->push_back(std::make_pair(0, 4));
   p->push_back(std::make_pair(4, 34));
   p->push_back(std::make_pair(0, 15));
   p->push_back(std::make_pair(15, 19));

   all_points_ = CreateCharacters(1.0f);
   character_width_ = DXROIDS_CHARACTER_WIDTH;
   character_height_ = DXROIDS_CHARACTER_HEIGHT;
}

void dxroids::CharacterRenderer::DrawLines(
   ID2D1RenderTarget * _target, 
   ID2D1Brush * _brush,
   D2D1_POINT_2F const & _base,
   point_list_type const & _points, 
   float _scale)
{
   for (std::pair<int, int> p : _points)
   {   
      D2D1_POINT_2F first = all_points_[p.first];
      first.x *= _scale;
      first.y *= _scale;

      D2D1_POINT_2F second = all_points_[p.second];
      second.x *= _scale;
      second.y *= _scale;

      _target->DrawLine(D2D1::Point2F(first.x + _base.x, first.y + _base.y),
         D2D1::Point2F(second.x + _base.x, second.y + _base.y),  _brush);
   }      
}

void dxroids::CharacterRenderer::DrawString(ID2D1RenderTarget * _target, ID2D1Brush * _brush,
   D2D1_POINT_2F const & _point, char * const _string, float _scale, Anchor _anchor)
{
   int const length = static_cast<int>(strlen(_string));  

   D2D1_POINT_2F curr_pos = _point;
   if (_anchor == Anchor::Right)
   {
      curr_pos.x -= (character_width_ * _scale) * length;
   }
   else if (_anchor == Anchor::Center)
   {
      curr_pos.x -= (character_width_ * _scale) * (length / 2);
   }

   for (int i = 0; i < length; ++i)   
   {
      char const ch = _string[i];
      if (ch == '\r' || ch == '\n')
      {
         curr_pos.x = _point.x;
         curr_pos.y = curr_pos.y + (character_height_ * _scale);
      }
      else if (ch == ' ')
      {         
         curr_pos.x += (character_width_ * _scale);
      }
      else
      {
         DrawLines(_target, _brush, curr_pos, line_lists_[ToIndex(ch)], _scale);
         curr_pos.x += (character_width_ * _scale);
      }
   }
}

